package com.ynet.middleground.mobile.approve.service;

import java.util.*;
import java.util.stream.Collectors;

import org.apache.commons.lang3.StringUtils;
import org.apache.dubbo.config.annotation.Reference;
import org.dozer.Mapper;
import org.springframework.beans.factory.annotation.Autowired;
import org.springframework.stereotype.Service;

import com.google.common.base.Throwables;
import com.ynet.core.common.PagerInfo;
import com.ynet.core.common.ServiceResult;
import com.ynet.core.exception.BusinessException;
import com.ynet.core.log.IfpLogger;
import com.ynet.core.util.IDUtil;
import com.ynet.middleground.approve.bean.QueryTaskDetailReq;
import com.ynet.middleground.approve.constant.WorkflowConstants;
import com.ynet.middleground.approve.dto.NextTaskDTO;
import com.ynet.middleground.approve.dto.TaskDTO;
import com.ynet.middleground.approve.service.ProcessTaskService;
import com.ynet.middleground.mobile.approve.constant.ErrorMessageConstant;
import com.ynet.middleground.mobile.approve.constant.SystemConstant;
import com.ynet.middleground.mobile.approve.request.BaseTaskReq;
import com.ynet.middleground.mobile.approve.response.ApprovePersonDTO;
import com.ynet.middleground.mobile.approve.response.ChannelFormatDTO;
import com.ynet.middleground.mobile.approve.response.UserDTO;
import com.ynet.middleground.mobile.approve.response.UserInfoDTO;
import com.ynet.middleground.mobile.approve.utils.CommUtils;
import com.ynet.middleground.user.bean.*;
import com.ynet.middleground.user.dto.*;
import com.ynet.middleground.user.service.*;

/**
 * @author liulx
 * @description TODO
 * @date 2020-12-18 17:10
 */
@Service
public class UserCenterService {

    @Reference(version = "0.0.1", check = false)
    UserService userService;

    @Reference(version = "0.0.1", check = false)
    ChannelService channelService;

    @Reference(version = "0.0.1", check = false)
    OrganizationManagementService organizationManagementService;

    @Reference(version = "0.0.1", check = false)
    private RoleManagementService roleManagementService;

    @Reference(version = "0.0.1", check = false)
    ProcessTaskService processTaskService;

    @Reference(version = "0.0.1", check = false)
    private UserRoleRelationService userRoleRelationService;

    @Autowired
    AuthService authService;

    @Autowired
    private Mapper dozerBeanMapper;

    @Autowired
    private ApproveCenterService approveCenterService;

    /**
     * 机构/部门默认父类id
     */
    private static final Integer ORGANIZATIONAL_PARENT_ID = 0;

    /**
     * 查询审批人
     *
     * @param req
     * @return
     */
    public List<ApprovePersonDTO> getApproveEmployees(BaseTaskReq req) {
        IfpLogger.info(Thread.currentThread().getStackTrace()[1].getMethodName(), "移动审批【查询审批人】服务 req：{}",
            req.toString());
        // step1: 参数准备
        // step1.1: 接收用户中台数据的变量
        ServiceResult<List<DingTalkSearchEmployeesDTO>> resp = new ServiceResult<>();
        List<DingTalkSearchEmployeesDTO> employeeDTOS = new ArrayList<>();
        // step1.2: 返回给移动审批前端的变量
        List<ApprovePersonDTO> approvePersonDTOS = new ArrayList<>(10);
        // step1.3: 查询参数:一般查询参数
        DingTalkSearchEmployeesInfoReq searchReq = new DingTalkSearchEmployeesInfoReq();
        searchReq.setTraceId(IDUtil.getSecureRandomId());
        searchReq.setOperationUserId(req.getUserId());
        searchReq.setRequestTime(new Date());
        searchReq.setChannel(SystemConstant.CHANNEL);
        // 其它参数
        String operateChannels = null;

        // 查询当前任务信息(主要获取流程变量)
        TaskDTO taskDTO = approveCenterService.getTask(req.getUserId(), req.getTaskId());
        // 查询下一任务信息(主要获取审批人/候选人/候选组等信息)
        NextTaskDTO nextTaskDTO = getNextTask(req.getUserId(), req.getTaskId());
        IfpLogger.info(Thread.currentThread().getStackTrace()[1].getMethodName(), "移动审批【查询下一任务信息】服务，主要用于获取下一节点审批人信息：{}",
            nextTaskDTO);
        if (taskDTO != null) {
            // 从流程变量里取出可操作渠道
            Map<String, Object> map = taskDTO.getProcessVariables();
            operateChannels = (String)map.get(WorkflowConstants.FLOW_CAN_OPERATE_CHANNEL_SIGNAL);
        }

        // step2: 转调用户中心
        resp = getApprovers(operateChannels, req.getUserId(), nextTaskDTO.getAssignee(),
            nextTaskDTO.getCandidateUsers(), nextTaskDTO.getCandidateGroups());
        if (resp != null) {
            employeeDTOS = resp.getResult();
        }

        // step3: 整理结果并返回
        for (DingTalkSearchEmployeesDTO d : employeeDTOS) {
            ApprovePersonDTO dto = new ApprovePersonDTO();
            dto = dozerBeanMapper.map(d, ApprovePersonDTO.class);
            approvePersonDTOS.add(dto);
            dto = null;
        }
        approvePersonDTOS = parentAndChildren(approvePersonDTOS);
        IfpLogger.info(Thread.currentThread().getStackTrace()[1].getMethodName(), "移动审批【查询审批人】服务，返回结果 resp：{}",
            approvePersonDTOS.toString());
        return approvePersonDTOS;
    }

    /**
     * 获取人员
     *
     * @param operateChannels 渠道列表，支持多个，以英文逗号隔开
     * @param userId 当前操作人
     * @param assignee 审批人
     * @param candidateUsers 候选人
     * @param candidateGroups 候选组
     * @return
     */
    private ServiceResult<List<DingTalkSearchEmployeesDTO>> getApprovers(String operateChannels, Integer userId,
        String assignee, List<String> candidateUsers, List<String> candidateGroups) {
        // step1: 准备参数
        // 返回对象
        ServiceResult<List<DingTalkSearchEmployeesDTO>> resp = new ServiceResult<>();
        // 请求对象
        DingTalkSearchEmployeesInfoReq searchReq = new DingTalkSearchEmployeesInfoReq();
        searchReq.setTraceId(IDUtil.getSecureRandomId());
        searchReq.setOperationUserId(userId);
        searchReq.setRequestTime(new Date());
        searchReq.setChannel(SystemConstant.CHANNEL);
        // 其它参数
        List<String> organizations = new ArrayList<>(10);
        List<String> roles = new ArrayList<>(10);
        Boolean queryAllFlag = false;

        // 是否查询可操作渠道下全部用户标记
        if (!StringUtils.isEmpty(assignee)) {
            if (candidateUsers == null || candidateUsers.size() == 0) {
                if (candidateGroups == null || candidateGroups.size() == 0) {
                    queryAllFlag = true;
                }
            }
        }
        // 对候选人处理一下，处理成：u-550
        List<String> users = new ArrayList<>(10);
        if (candidateUsers == null || candidateUsers.size() == 0) {
            candidateUsers = new ArrayList<>(10);
        }
        if (!StringUtils.isEmpty(assignee)) {
            candidateUsers.add(assignee);
        }
        for (String u : candidateUsers) {
            users.add("u-" + u);
        }
        // 要把候选人的角色，添加进来：
        if (candidateUsers.size() > 0) {
            if (candidateGroups == null && candidateGroups.size() == 0) {
                candidateGroups = new ArrayList<>(10);
            }
            for (String user : candidateUsers) {
                if (CommUtils.isInteger(user)) {
                    List<String> groupIds = listUserGroupsByUserId(Integer.parseInt(user), SystemConstant.CHANNEL,
                        Integer.parseInt(user), null);
                    candidateGroups.addAll(groupIds);
                }
            }
        }

        // 要对候选组处理一下，样例：把[d:1,dr:1-6]处理成[d:1],[dr:1-6]两组
        for (String s : candidateGroups) {
            if ("dr".equals(s.substring(0, 2))) {
                // 角色
                roles.add(s);
            } else if ("er".equals(s.substring(0, 2))) {
            } else {
                // 部门
                String organizationalId = s.substring(s.lastIndexOf(":") + 1);
                // 整理出部门的上下级
                organizations.add(s);
                List<String> parentAndChildOrganizations =
                    parentAndChildOrganizations(userId, operateChannels, Integer.parseInt(organizationalId));
                if (parentAndChildOrganizations != null && parentAndChildOrganizations.size() > 0) {
                    organizations.addAll(parentAndChildOrganizations);
                }
            }
        }
        // 去重
        users = users.stream().distinct().collect(Collectors.toList());
        organizations = organizations.stream().distinct().collect(Collectors.toList());
        roles = roles.stream().distinct().collect(Collectors.toList());

        // 候选人/候选组参数/可操作的渠道/是否查询可操作渠道下全部用户标记
        searchReq.setCanOperateChannels(Arrays.asList(operateChannels.split(",")));
        searchReq.setCandidateUsers(users);
        searchReq.setOrganizations(organizations);
        searchReq.setRoles(roles);
        searchReq.setQueryAllFlag(queryAllFlag);

        // step2 :转调用户中心并返回
        resp = organizationManagementService.queryEmployeesForMobile(searchReq);

        return resp;
    }

    /**
     * 获取港内组织上下级ID（移动审批专用）
     *
     * @param userId
     * @param operateChannels
     * @param id
     * @return
     */
    public List<String> parentAndChildOrganizations(Integer userId, String operateChannels, Integer id) {
        List<String> parentAndChildOrganizations = new ArrayList<>(10);
        ServiceResult<List<String>> serviceResult = new ServiceResult<>();
        GetParentAndChildReq req = new GetParentAndChildReq();
        req.setTraceId(IDUtil.getSecureRandomId());
        req.setOperationUserId(userId);
        req.setRequestTime(new Date());
        req.setChannel(SystemConstant.CHANNEL);
        req.setOperateChannels(operateChannels);
        req.setId(id);
        try {
            serviceResult = organizationManagementService.parentAndChildOrganizationIds(req);
        } catch (BusinessException e) {
            throw new BusinessException(e.getMessage(), e.getCode());
        } catch (Exception e) {
            IfpLogger.error(Thread.currentThread().getStackTrace()[1].getMethodName(),
                "获取港内组织上下级ID（移动审批专用）服务异常, case: {}", Throwables.getStackTraceAsString(e));
            throw new BusinessException(ErrorMessageConstant.ECUC0025_MESSAGE, ErrorMessageConstant.ECUC0025_CODE);
        }
        parentAndChildOrganizations = serviceResult.getResult();
        return parentAndChildOrganizations;
    }

    /**
     * 根据用户id查询用户所拥有的部门和部门角色集合 <br />
     *
     * @param userId 用户id
     * @param channel 渠道
     * @param operationUserId 操作人id
     * @param organId 机构id
     * @return 部门和部门角色总集合
     */
    public List<String> listUserGroupsByUserId(Integer userId, String channel, Integer operationUserId,
        Integer organId) {
        List<OrganRoleRelationshipDto> list = listUserRelationByUserId(userId, channel, operationUserId);
        if (organId != null) {
            // 过滤其他机构，只留取指定机构
            list = list.stream().filter(d -> d.getFirstOrganizational().equals(organId)).collect(Collectors.toList());
        }

        // 利用 TreeSet 的排序去重构造函数来达到去重元素的目的
        // 过滤重复的组织id
        ArrayList<OrganRoleRelationshipDto> groups = list.stream()
            .collect(Collectors.collectingAndThen(
                Collectors.toCollection(
                    () -> new TreeSet<>(Comparator.comparing(OrganRoleRelationshipDto::getOrganizationalId))),
                ArrayList::new));

        // 收集用户所拥有的部门id集合, 部门格式为 d:1001
        List<String> groupList =
            groups.stream().map(o -> WorkflowConstants.CANDIDATE_GROUP_DEPARTMENT_PREFIX + o.getOrganizationalId())
                .collect(Collectors.toList());

        // 利用 TreeSet 的排序去重构造函数来达到去重元素的目的
        // 根据 组织id-角色id 2个属性 去重复
        ArrayList<OrganRoleRelationshipDto> groupsRoles = list.stream()
            .collect(Collectors.collectingAndThen(
                Collectors.toCollection(
                    () -> new TreeSet<>(Comparator.comparing(o -> o.getOrganizationalId() + ";" + o.getRoleId()))),
                ArrayList::new));

        // 收集用户所拥有的 部门id、角色id 组合式 集合，部门格式为 dr:1001-1001
        List<String> groupRolesList = groupsRoles.stream()
            .map(o -> WorkflowConstants.CANDIDATE_GROUP_DEPARTMENT_ROLE_PREFIX + o.getOrganizationalId()
                + WorkflowConstants.CANDIDATE_GROUP_DEPARTMENT_ROLE_DELIMITER + o.getRoleId())
            .collect(Collectors.toList());

        // 合并部门、部门-角色集合
        groupList.addAll(groupRolesList);
        return groupList;
    }

    /**
     * 根据用户id查询用户所属部门、角色关系
     *
     * @param userId 用户Id
     * @param channel 渠道
     * @param operationUserId 操作人id
     * @return 关系列表
     */
    public List<OrganRoleRelationshipDto> listUserRelationByUserId(Integer userId, String channel,
        Integer operationUserId) {
        QueryOrganRoleRelationReq queryOrganRoleRelationReq = new QueryOrganRoleRelationReq();
        queryOrganRoleRelationReq.setUserId(userId);
        queryOrganRoleRelationReq.setTraceId(IDUtil.getSecureRandomId());
        queryOrganRoleRelationReq.setChannel(channel);
        queryOrganRoleRelationReq.setOperationUserId(operationUserId);
        queryOrganRoleRelationReq.setRequestTime(new Date());
        ServiceResult<List<OrganRoleRelationshipDto>> serviceResult;
        try {
            serviceResult = roleManagementService.queryOrganRoleRelationshipNoPage(queryOrganRoleRelationReq);
        } catch (BusinessException e) {
            throw new BusinessException(e.getMessage(), e.getCode());
        } catch (Exception e) {
            IfpLogger.error(Thread.currentThread().getStackTrace()[1].getMethodName(), "根据用户id查询用户所属部门、角色关系异常,case:{}",
                Throwables.getStackTraceAsString(e));
            throw new BusinessException(ErrorMessageConstant.ECUC0024_MESSAGE, ErrorMessageConstant.ECUC0024_CODE);
        }
        return getServiceResult(serviceResult);
    }

    /**
     * 获取需要推送消息的审批人列表
     *
     * @param operateChannels 可跨渠道列表 多个以英文,号隔开
     * @param userId 用户
     * @param assignee 任务处理人
     * @param candidateUsers 任务候选人列表
     * @param candidateGroups 任务候选组列表
     * @return 符合推送钉钉消息的人员列表
     */
    public List<ApprovePersonDTO> getMessagesApprover(String operateChannels, Integer userId, String assignee,
        List<String> candidateUsers, List<String> candidateGroups) {
        ServiceResult<List<DingTalkSearchEmployeesDTO>> serviceResult =
            getApprovers(operateChannels, userId, assignee, candidateUsers, candidateGroups);
        if (!serviceResult.isSuccess()) {
            IfpLogger.error(Thread.currentThread().getStackTrace()[1].getMethodName(), "查询可选审批人列表服务异常，异常原因: {}:{}",
                serviceResult.getErrorCode(), serviceResult.getErrorMsg());
            return null;
        }
        // 符合前端的层级关系的数据集合
        List<ApprovePersonDTO> respList = new ArrayList<>(10);
        List<DingTalkSearchEmployeesDTO> list = serviceResult.getResult();
        for (DingTalkSearchEmployeesDTO d : list) {
            ApprovePersonDTO dto = dozerBeanMapper.map(d, ApprovePersonDTO.class);
            respList.add(dto);
        }
        // 整理层级关系
        respList = parentAndChildren(respList);
        List<ApprovePersonDTO> userList = new ArrayList<>();
        for (ApprovePersonDTO dto : respList) {
            setUsers(dto, userList);
        }
        // 根据 id 再去重复
        return userList.stream()
            .collect(Collectors.collectingAndThen(
                Collectors.toCollection(() -> new TreeSet<>(Comparator.comparing(ApprovePersonDTO::getId))),
                ArrayList::new));
        // 过滤，只获取用户及有 otherMessage 内容的，此时 otherMessage 为钉钉账号
        /*return list.stream().filter(emp -> "4".equals(emp.getType()) && StringUtils.isNotBlank(emp.getOtherMessage()))
            .collect(Collectors.toList());*/
    }

    /**
     * 提取要发生信息的用户
     *
     * @param dto
     * @param userList
     */
    private void setUsers(ApprovePersonDTO dto, List<ApprovePersonDTO> userList) {
        if ("4".equals(dto.getType()) && StringUtils.isNotBlank(dto.getOtherMessage())) {
            userList.add(dto);
        } else {
            List<ApprovePersonDTO> childList = dto.getChild();
            for (ApprovePersonDTO child : childList) {
                setUsers(child, userList);
            }
        }
    }

    /**
     * 查询下一任务
     *
     * @return
     */
    private NextTaskDTO getNextTask(Integer userId, String taskId) {
        // step1: 参数准备
        ServiceResult<NextTaskDTO> result = new ServiceResult<>();
        NextTaskDTO nextTaskDTO = null;
        QueryTaskDetailReq searchReq = new QueryTaskDetailReq();
        searchReq.setTraceId(IDUtil.getSecureRandomId());
        searchReq.setOperationUserId(userId);
        searchReq.setRequestTime(new Date());
        searchReq.setChannel(SystemConstant.CHANNEL);
        searchReq.setTaskId(taskId);

        // step2: 转调审批中心并返回数据
        result = processTaskService.getNextTask(searchReq);
        if (result != null) {
            nextTaskDTO = result.getResult();
        }
        if (nextTaskDTO == null) {
            throw new BusinessException(ErrorMessageConstant.ECUC0021_MESSAGE, ErrorMessageConstant.ECUC0021_CODE);
        }
        return nextTaskDTO;
    }

    /**
     * 整理组织架构
     *
     * @param list
     * @return
     */
    private List<ApprovePersonDTO> parentAndChildren(List<ApprovePersonDTO> list) {

        // 最顶层节点
        List<ApprovePersonDTO> rootList = new ArrayList<>();
        // 非最顶层节点
        List<ApprovePersonDTO> bodyList = new ArrayList<>();
        for (ApprovePersonDTO approvePersonDTO : list) {
            if (StringUtils.isEmpty(approvePersonDTO.getParentId())) {
                rootList.add(approvePersonDTO);
            } else {
                bodyList.add(approvePersonDTO);
            }
        }
        List<ApprovePersonDTO> roots = getTree(rootList, bodyList);
        roots =
            roots.stream().filter(r -> r.getChild() != null && r.getChild().size() > 0).collect(Collectors.toList());
        return roots;
    }

    /**
     * 整理树形结构
     *
     * @param rootList
     * @param bodyList
     * @return
     */
    public List<ApprovePersonDTO> getTree(List<ApprovePersonDTO> rootList, List<ApprovePersonDTO> bodyList) {
        if (bodyList == null || bodyList.size() == 0) {
            return rootList;
        } else {
            // 声明一个map，用来过滤已操作过的数据
            Map<String, String> map = new HashMap<>(bodyList.size());
            rootList.forEach(parent -> getChild(parent, bodyList, map));
            return rootList;
        }
    }

    /**
     * getChild
     *
     * @param parent
     * @param bodyList
     * @param map
     */
    private void getChild(ApprovePersonDTO parent, List<ApprovePersonDTO> bodyList, Map<String, String> map) {
        List<ApprovePersonDTO> childList = new ArrayList<>();
        bodyList.stream().filter(c -> !map.containsKey(c.getUniqueKey()))
            .filter(c -> c.getParentId().equals(parent.getId())).forEach(c -> {
                getChild(c, bodyList, map);
                if (!"4".equals(c.getType()) && !c.getChild().isEmpty()) {
                    childList.add(c);
                } else if ("4".equals(c.getType())) {
                    c.setId(c.getUniqueKey() + "-" + c.getId());
                    childList.add(c);
                }
                map.put(c.getUniqueKey(), c.getName());
            });
        parent.setChild(childList);
    }

    /**
     * 调用用户中心"港内员工数据查询"服务
     *
     * @param userId
     * @param channel
     * @return
     */
    public List<EmployeeInfoDto> queryEmployee(Integer userId, String channel, String telephone) {
        userId = userId == null ? 0 : userId;
        // Step1: 准备查询条件
        QueryEmployeesInfoReq req = new QueryEmployeesInfoReq();
        req.setTraceId(IDUtil.getSecureRandomId());
        req.setOperationUserId(userId);
        req.setRequestTime(new Date());
        req.setChannel(channel);
        req.setUserId(userId);
        req.setTelephone(telephone);
        req.setPagerInfo(new PagerInfo());
        // 赋值queryChannel
        String queryChannel = null;
        List<String> channelList = new ArrayList<>();
        List<ChannelDTO> channelDTOs = this.channelList();
        if (channelDTOs.size() > 0 && channelDTOs != null) {
            for (ChannelDTO c : channelDTOs) {
                channelList.add(c.getChannelCode());
            }
            queryChannel = channelList.stream().collect(Collectors.joining(","));
        }
        req.setQueryChannel(queryChannel);
        // Step2: 调用用户中心服务,并返回结果
        ServiceResult<List<EmployeeInfoDto>> serviceResult;
        List<EmployeeInfoDto> list = null;

        IfpLogger.info(Thread.currentThread().getStackTrace()[1].getMethodName(), "港内员工数据查询服务,reqParams: {}",
            req.toString());
        serviceResult = organizationManagementService.queryEmployee(req);
        if (serviceResult != null) {
            list = serviceResult.getResult();
        }
        return list;
    }

    /**
     * 调用用户中心"港内员工数据查询（不分页)"服务
     *
     * @param userId
     * @param channel
     * @return
     */
    public List<DingTalkSearchOrgRelationDTO> queryAllEmployees(Integer userId, String channel,
        Integer organizationalId, Integer roleId, String queryChannel) {
        // Step1: 准备查询条件
        QueryDingTalkEmployeesInfoReq req = new QueryDingTalkEmployeesInfoReq();
        req.setTraceId(IDUtil.getSecureRandomId());
        req.setOperationUserId(userId);
        req.setRequestTime(new Date());
        req.setChannel(channel);

        req.setOrganizationalId(organizationalId);
        req.setRoleId(roleId);
        req.setQueryChannel(queryChannel);

        // Step2: 调用用户中心服务,并返回结果
        ServiceResult<List<DingTalkSearchOrgRelationDTO>> serviceResult = new ServiceResult<>();
        List<DingTalkSearchOrgRelationDTO> list = null;
        try {
            IfpLogger.info(Thread.currentThread().getStackTrace()[1].getMethodName(), "港内员工数据查询（不分页)服务,reqParams: {}",
                req.toString());
            serviceResult = organizationManagementService.queryDingTalkEmployee(req);
            if (serviceResult != null) {
                list = serviceResult.getResult();
            }
        } catch (BusinessException e) {
            throw new BusinessException(e.getMessage(), e.getCode());
        } catch (Exception e) {
            throw new BusinessException(ErrorMessageConstant.ECUC0009_MESSAGE, ErrorMessageConstant.ECUC0009_CODE);
        }
        return list;
    }

    /**
     * 查询用户信息
     *
     * @param userId 用户id
     * @param channel 渠道
     * @param operationUserId 操作人id
     * @param enterpriseId 用户所属企业 id
     * @return 查询用户信息
     */
    public UserInfoDto getUserInfo(Integer userId, String channel, Integer operationUserId, Integer enterpriseId) {
        QueryUserInfoReq req = new QueryUserInfoReq();
        req.setUserId(userId);
        req.setEnterpriseId(enterpriseId);
        req.setPagerInfo(new PagerInfo());
        req.setTraceId(IDUtil.getSecureRandomId());
        req.setChannel(channel);
        req.setOperationUserId(operationUserId);
        req.setRequestTime(new Date());
        ServiceResult<List<UserInfoDto>> serviceResult;
        try {
            IfpLogger.info(Thread.currentThread().getStackTrace()[1].getMethodName(), "移动审批调用查询用户信息服务,reqParams: {}",
                req.toString());
            serviceResult = userService.queryUserInfo(req);
        } catch (BusinessException e) {
            throw new BusinessException(e.getMessage(), e.getCode());
        } catch (Exception e) {
            IfpLogger.error(Thread.currentThread().getStackTrace()[1].getMethodName(), "移动审批调用查询用户信息服务异常, case: {}",
                Throwables.getStackTraceAsString(e));
            throw new BusinessException("用户中心服务调用失败", "ECCT0002");
        }
        List<UserInfoDto> result = getServiceResult(serviceResult);
        if (result == null || result.size() == 0) {
            throw new BusinessException("用户不存在", "ECCT0005");
        }
        return result.get(0);
    }

    /**
     * 根据用户钉钉 id 获取用户信息
     *
     * @param userId 用户 id
     * @param dingtalkUserid 用户钉钉 id
     * @return 用户信息传输对象
     */
    public UserInfoDTO getUserInfoByDingTalkUserId(Integer userId, String dingtalkUserid) {
        UserInfoDto userInfo = getUserInfo(userId, SystemConstant.CHANNEL, userId, null);
        if (userInfo == null || userInfo.getUserBaseInformationDto() == null) {
            throw new BusinessException("无该用户信息", "ECMA0001");
        }
        String talkUserid = userInfo.getUserBaseInformationDto().getDingtalkUserid();
        if (!talkUserid.equals(dingtalkUserid)) {
            throw new BusinessException("该钉钉账户与用户信息不匹配", "ECMA0001");
        }
        UserDTO user = authService.getUser(dingtalkUserid);
        UserInfoDTO dto = new UserInfoDTO();
        dto.setMobile(user.getMobile());
        dto.setAvatarUrl(user.getAvatar());
        dto.setEmail(userInfo.getUserBaseInformationDto().getEmail());
        dto.setName(userInfo.getUserBaseInformationDto().getUserName());
        return dto;
    }

    /**
     * 绑定钉钉账号
     *
     * @param userId 用户中台 userid
     * @param dingtalkUserid 钉钉账号 id
     * @param channel 渠道
     */
    public void bindDingtalk(Integer userId, String dingtalkUserid, String channel) {
        BindDingDingReq req = new BindDingDingReq();
        req.setUserId(userId);
        req.setDingtalkUserid(dingtalkUserid);
        req.setTraceId(IDUtil.getSecureRandomId());
        req.setChannel(channel);
        req.setOperationUserId(userId);
        req.setRequestTime(new Date());
        ServiceResult<String> result = userService.bindDingTalk(req);
        if (result != null && !result.isSuccess()) {
            throw new BusinessException("绑定钉钉账号失败", "ECMA0001");
        }
    }

    /**
     * 查询所有渠道信息
     *
     * @return
     */
    public List<ChannelDTO> channelList() {
        ServiceResult<List<ChannelDTO>> serviceResult = channelService.searchAllChannel();
        return getServiceResult(serviceResult);
    }

    /**
     * 获取渠道详情信息
     *
     * @param channelCode 渠道码
     * @param userId 当前用户 id
     * @return 渠道信息对象
     */
    public ChannelDTO getChannelDetail(String channelCode, Integer userId) {
        QueryChannelByCodeReq req = new QueryChannelByCodeReq();
        req.setChannelCode(channelCode);
        req.setTraceId(IDUtil.getSecureRandomId());
        req.setChannel(SystemConstant.CHANNEL);
        req.setOperationUserId(userId);
        req.setRequestTime(new Date());
        return getServiceResult(channelService.queryChannelByCode(req));
    }

    /**
     * 获取 ServiceResult 结果值
     *
     * @param serviceResult 服务返回结果对象
     * @param <T> 返回对象数据中具体的数据类型
     * @return ServiceResult 结果值
     */
    private <T> T getServiceResult(ServiceResult<T> serviceResult) {
        Optional.ofNullable(serviceResult).orElseThrow(() -> new BusinessException("用户中心服务调用失败", "ECCT0002"));
        if (serviceResult.isSuccess()) {
            return serviceResult.getResult();
        }
        throw new BusinessException(serviceResult.getErrorMsg(), serviceResult.getErrorCode());
    }

    /**
     * 查询所有渠道下业态 2023-03-13 syf
     * 
     * @return
     */
    public List<ChannelFormatDTO> getChannelFormatList(Integer userId) {
        // 查询所有渠道
        List<ChannelDTO> channelDTOList = channelService.searchAllChannel().getResult();
        // 查询所有业态
        QueryOrganizationalStructureReq req = new QueryOrganizationalStructureReq();
        req.setChannel(SystemConstant.CHANNEL);
        req.setRequestTime(new Date());
        req.setOperationUserId(userId);
        req.setTraceId(IDUtil.getSecureRandomId());
        req.setParentId(0);
        PagerInfo pagerInfo = new PagerInfo();
        pagerInfo.setPageSize(100000);
        pagerInfo.setPageNum(1);
        req.setPagerInfo(pagerInfo);
        List<OrganizationalStructureDto> orgList =
            organizationManagementService.queryOrganizationalStructureInfo(req).getResult();
        List<ChannelFormatDTO> channelFormatDTOList = new ArrayList<>();
        // 插入一个全部渠道，作为第一个
        ChannelFormatDTO channelAll = new ChannelFormatDTO();
        channelAll.setParent(String.valueOf(ORGANIZATIONAL_PARENT_ID));
        channelAll.setName("全部");
        channelAll.setValue("-");
        channelFormatDTOList.add(channelAll);

        // 第一个全部渠道下必须有子集，否则前端无法展示渲染，故添加 1 个全部业态
        ChannelFormatDTO channelAllFormat = new ChannelFormatDTO();
        channelAllFormat.setParent("-");
        channelAllFormat.setName("全部");
        channelAllFormat.setValue("");
        channelFormatDTOList.add(channelAllFormat);
        // 将渠道加入返回对象
        for (ChannelDTO channelDTO : channelDTOList) {
            ChannelFormatDTO channelFormatDTO = new ChannelFormatDTO();
            channelFormatDTO.setParent(String.valueOf(ORGANIZATIONAL_PARENT_ID));
            channelFormatDTO.setName(channelDTO.getChannelName());
            channelFormatDTO.setValue(channelDTO.getChannelCode());
            channelFormatDTOList.add(channelFormatDTO);
            // 插入一个全部业态
            ChannelFormatDTO allFormatDTO = new ChannelFormatDTO();
            allFormatDTO.setParent(channelDTO.getChannelCode());
            allFormatDTO.setName("全部");
            allFormatDTO.setValue(channelDTO.getChannelCode());
            channelFormatDTOList.add(allFormatDTO);
        }
        // 将业态加入返回对象
        for (OrganizationalStructureDto org : orgList) {
            ChannelFormatDTO channelFormatDTO = new ChannelFormatDTO();
            channelFormatDTO.setParent(org.getChannel());
            channelFormatDTO.setName(org.getOrganizationalName());
            channelFormatDTO.setValue(org.getOrganizationalId());
            channelFormatDTOList.add(channelFormatDTO);
        }
        return channelFormatDTOList;
    }
}
